home *** CD-ROM | disk | FTP | other *** search
/ Aminet 34 / Aminet 34 (2000)(Schatztruhe)[!][Dec 1999].iso / Aminet / util / gnu / unixcmds.lha / unixcmds / src / date.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-06  |  12.0 KB  |  417 lines

  1. /* date - Display (or set) the date and time            Author: V. Archer */
  2.  
  3. #include <sys/types.h>
  4. #include <ctype.h>
  5. #include <stddef.h>
  6. #include <stdlib.h>
  7. #include <time.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10.  
  11. #define MIN     60L             /* # seconds in a minute */
  12. #define HOUR    (60 * MIN)      /* # seconds in an hour */
  13. #define DAY     (24 * HOUR)     /* # seconds in a day */
  14. #define YEAR    (365 * DAY)     /* # seconds in a (non-leap) year */
  15.  
  16. int qflag, uflag, sflag;
  17.  
  18. /* Default output file descriptor.
  19.  */
  20. int outfd = 1;
  21.  
  22. int main  (int argc, char **argv);
  23. void putchar  (int c);
  24. void pstring  (char *s, int len);
  25. void pldecimal  (unsigned long d, int digits);
  26. void pdecimal  (int d, int digits);
  27. void fmtdate  (char *format, time_t t, struct tm *p);
  28. time_t make_time  (char *t);
  29. void usage  (void);
  30.  
  31. /* Main module. Handles P1003.2 date and system administrator's date. The
  32.  * date entered should be given GMT, regardless of the system's TZ!
  33.  */
  34. int main(argc, argv)
  35. /* [<][>][^][v][top][bottom][index][help] */
  36. int argc;
  37. char **argv;
  38. {
  39.   time_t t;
  40.   char *format;
  41.   char time_buf[40];
  42.   int n;
  43.   int i;
  44.  
  45.   time(&t);
  46.  
  47.   i = 1;
  48.   while (i < argc && argv[i][0] == '-') {
  49.         char *opt = argv[i++] + 1, *end;
  50.  
  51.         if (opt[0] == '-' && opt[1] == 0) break;
  52.  
  53.         while (*opt != 0) switch (*opt++) {
  54.         case 'q':
  55.                 qflag = 1;
  56.                 break;
  57.         case 's':
  58.                 sflag = 1;
  59.                 break;
  60.         case 'u':
  61.                 uflag = 1;
  62.                 break;
  63.         case 't':
  64.                 if (*opt == 0) {
  65.                         if (i == argc) usage();
  66.                         opt = argv[i++];
  67.                 }
  68.                 t = strtoul(opt, &end, 10);
  69.                 if (*end != 0) usage();
  70.                 opt = "";
  71.                 break;
  72.         }
  73.   }
  74.  
  75.   if (!qflag && i < argc && ('0' <= argv[i][0] && argv[i][0] <= '9')) {
  76.         t = make_time(argv[i++]);
  77.         sflag = 1;
  78.   }
  79.  
  80.   format = "%c";
  81.   if (i < argc && argv[i][0] == '+') format = argv[i++] + 1;
  82.  
  83.   if (i != argc) usage();
  84.  
  85.   if (qflag) {
  86.         pstring("\nPlease enter date: MMDDYYhhmmss. Then hit the RETURN key.\n", -1);
  87.         n = read(0, time_buf, sizeof(time_buf));
  88.         if (n > 0 && time_buf[n-1] == '\n') n--;
  89.         if (n >= 0) time_buf[n] = 0;
  90.         t = make_time(time_buf);
  91.         sflag = 1;
  92.   }
  93.   if (sflag)
  94.    {
  95.         pstring("Amiga version: use the time command\n", -1);
  96.         return(1);
  97.    }
  98.  
  99. /*  if (sflag && stime(&t) != 0) {
  100.         outfd = 2;
  101.         pstring("No permission to set time\n", -1);
  102.         return(1);
  103.   }*/
  104.  
  105.   fmtdate(format, t, uflag ? gmtime(&t) : localtime(&t));
  106.   putchar('\n');
  107.   return(0);
  108. }
  109.  
  110. /* Replacement for stdio putchar().
  111.  */
  112. /*void putchar(c)
  113. int c;
  114. {
  115.   static char buf[1024];
  116.   static char *bp = buf;
  117.  
  118.   if (c != 0) *bp++ = c;
  119.   if (c == 0 || c == '\n' || bp == buf + sizeof(buf)) {
  120.         write(outfd, buf, bp - buf);
  121.         bp = buf;
  122.   }
  123. }
  124. */
  125.  
  126. /* Internal function that prints a n-digits number. Replaces stdio in our
  127.  * specific case.
  128.  */
  129. void pldecimal(d, digits)
  130. /* [<][>][^][v][top][bottom][index][help] */
  131. unsigned long d;
  132. int digits;
  133. {
  134.   digits--;
  135.   if (d > 9 || digits > 0) pldecimal(d / 10, digits);
  136.   putchar('0' + (d % 10));
  137. }
  138.  
  139. void pdecimal(d, digits)
  140. /* [<][>][^][v][top][bottom][index][help] */
  141. int d, digits;
  142. {
  143.   pldecimal((unsigned long) d, digits);
  144. }
  145.  
  146. /* Internal function that prints a fixed-size string. Replaces stdio in our
  147.  * specific case.
  148.  */
  149. void pstring(s, len)
  150. /* [<][>][^][v][top][bottom][index][help] */
  151. char *s;
  152. int len;
  153. {
  154.  
  155.   while ((*s)!='\0')
  156.         if (len--)
  157.                 {putchar(*s);s++;}
  158.         else
  159.                 break;
  160. }
  161.  
  162. /* Format the date, using the given locale string. A special case is the
  163.  * TZ which might be a sign followed by four digits (New format time zone).
  164.  */
  165. void fmtdate(format, t, p)
  166. /* [<][>][^][v][top][bottom][index][help] */
  167. char *format;
  168. time_t t;
  169. struct tm *p;
  170. {
  171.   int i;
  172.   char *s;
  173.   static char *wday[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
  174.                        "Thursday", "Friday", "Saturday"};
  175.   static char *month[] = {"January", "February", "March", "April",
  176.                         "May", "June", "July", "August",
  177.                     "September", "October", "November", "December"};
  178.  
  179.   p= uflag ? gmtime(&t) : localtime(&t);
  180.  
  181.   while (*format)
  182.         if (*format == '%') {
  183.                 switch (*++format) {
  184.                     case 'A':
  185.                         pstring(wday[p->tm_wday], -1);
  186.                         break;
  187.                     case 'B':
  188.                         pstring(month[p->tm_mon], -1);
  189.                         break;
  190.                     case 'D':
  191.                         pdecimal(p->tm_mon + 1, 2);
  192.                         putchar('/');
  193.                         pdecimal(p->tm_mday, 2);
  194.                         putchar('/');
  195.                     case 'y':
  196.                         pdecimal(p->tm_year % 100, 2);
  197.                         break;
  198.                     case 'H':
  199.                         pdecimal(p->tm_hour, 2);
  200.                         break;
  201.                     case 'I':
  202.                         i = p->tm_hour % 12;
  203.                         pdecimal(i ? i : 12, 2);
  204.                         break;
  205.                     case 'M':
  206.                         pdecimal(p->tm_min, 2);
  207.                         break;
  208.                     case 'X':
  209.                     case 'T':
  210.                         pdecimal(p->tm_hour, 2);
  211.                         putchar(':');
  212.                         pdecimal(p->tm_min, 2);
  213.                         putchar(':');
  214.                     case 'S':
  215.                         pdecimal(p->tm_sec, 2);
  216.                         break;
  217.                     case 'U':
  218.                         pdecimal((p->tm_yday - p->tm_wday + 13) / 7, 2);
  219.                         break;
  220.                     case 'W':
  221.                         if (--(p->tm_wday) < 0) p->tm_wday = 6;
  222.                         pdecimal((p->tm_yday - p->tm_wday + 13) / 7, 2);
  223.                         if (++(p->tm_wday) > 6) p->tm_wday = 0;
  224.                         break;
  225.                     case 'Y':
  226.                         pdecimal(p->tm_year + 1900, 4);
  227.                         break;
  228.                     case 'Z':
  229.                         if (uflag) {
  230.                                 s = "GMT";
  231.                         } else {
  232.                                 s = (p->tm_isdst == 1) ? tzname[1] : tzname[0];
  233.                         }
  234.                         pstring(s, strlen(s));
  235.                         break;
  236.                     case 'a':
  237.                         pstring(wday[p->tm_wday], 3);
  238.                         break;
  239.                     case 'b':
  240.                     case 'h':
  241.                         pstring(month[p->tm_mon], 3);
  242.                         break;
  243.                     case 'c':
  244.                         if (!(s = getenv("LC_TIME")))
  245.                                 s = "%a %b %e %T %Z %Y";
  246.                         fmtdate(s, t, p);
  247.                         break;
  248.                     case 'd':
  249.                         pdecimal(p->tm_mday, 2);
  250.                         break;
  251.                     case 'e':
  252.                         if (p->tm_mday < 10) putchar(' ');
  253.                         pdecimal(p->tm_mday, 1);
  254.                         break;
  255.                     case 'j':
  256.                         pdecimal(p->tm_yday + 1, 3);
  257.                         break;
  258.                     case 'm':
  259.                         pdecimal(p->tm_mon + 1, 2);
  260.                         break;
  261.                     case 'n':   putchar('\n');  break;
  262.                     case 'p':
  263.                         if (p->tm_hour < 12)
  264.                                 putchar('A');
  265.                         else
  266.                                 putchar('P');
  267.                         putchar('M');
  268.                         break;
  269.                     case 'r':
  270.                         fmtdate("%I:%M:%S %p", t, p);
  271.                         break;
  272.                     case 's':
  273.                         pldecimal((unsigned long) t, 0);
  274.                         break;
  275.                     case 't':   putchar('\t');  break;
  276.                     case 'w':
  277.                         putchar('0' + p->tm_wday);
  278.                         break;
  279.                     case 'x':
  280.                         fmtdate("%B %e %Y", t, p);
  281.                         break;
  282.                     case '%':   putchar('%');   break;
  283.                     case '\0':  format--;
  284.                 }
  285.                 format++;
  286.         } else
  287.                 putchar(*format++);
  288. }
  289.  
  290. /* Convert a local date string into GMT time in seconds. */
  291. time_t make_time(t)
  292. /* [<][>][^][v][top][bottom][index][help] */
  293. char *t;
  294. {
  295.   struct tm tm;                         /* user specified time */
  296.   time_t now;                           /* current time */
  297.   int leap;                             /* current year is leap year */
  298.   int i;                                /* general index */
  299.   int fld;                              /* number of fields */
  300.   int f[6];                             /* time fields */
  301.   static int days_per_month[2][12] = {
  302.   { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  303.   { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }};
  304.  
  305. /* Get current time just in case */
  306.   now = time((time_t *) 0);
  307.   tm  = *localtime(&now);
  308.   tm.tm_sec   = 0;
  309.   tm.tm_mon++;
  310.   tm.tm_year %= 100;
  311.  
  312. /* Parse the time */
  313. #if '0'+1 != '1' || '1'+1 != '2' || '2'+1 != '3' || '3'+1 != '4' || \
  314.     '4'+1 != '5' || '5'+1 != '6' || '6'+1 != '7' || '7'+1 != '8' || '8'+1 != '9'
  315.   << Code unsuitable for character collating sequence >>
  316. #endif
  317.  
  318.   for (fld = 0; fld < sizeof(f)/sizeof(f[0]); fld++) {
  319.         if (*t == 0) break;
  320.         f[fld] = 0;
  321.         for (i = 0; i < 2; i++, t++) {
  322.                 if (*t < '0' || *t > '9') usage();
  323.                 f[fld] = f[fld] * 10 + *t - '0';
  324.         }
  325.   }
  326.  
  327.   switch (fld) {
  328.   case 2:
  329.         tm.tm_hour = f[0]; tm.tm_min  = f[1]; break;
  330.  
  331.   case 3:
  332.         tm.tm_hour = f[0]; tm.tm_min  = f[1]; tm.tm_sec  = f[2];
  333.         break;
  334.  
  335.   case 5:
  336.         tm.tm_mon  = f[0]; tm.tm_mday = f[1]; tm.tm_year = f[2];
  337.         tm.tm_hour = f[3]; tm.tm_min  = f[4];
  338.         break;
  339.  
  340.   case 6:
  341.         tm.tm_mon  = f[0]; tm.tm_mday = f[1]; tm.tm_year = f[2];
  342.         tm.tm_hour = f[3]; tm.tm_min  = f[4]; tm.tm_sec  = f[5];
  343.         break;
  344.  
  345.   default:
  346.         usage();
  347.   }
  348.  
  349. /* Convert the time into seconds since 1 January 1970 */
  350.   if (tm.tm_year < 70)
  351.     tm.tm_year += 100;
  352.   leap = (tm.tm_year % 4 == 0 && tm.tm_year % 400 != 0);
  353.   if (tm.tm_mon  < 1  || tm.tm_mon  > 12 ||
  354.       tm.tm_mday < 1  || tm.tm_mday > days_per_month[leap][tm.tm_mon-1] ||
  355.       tm.tm_hour > 23 || tm.tm_min  > 59) {
  356.     outfd = 2;
  357.     pstring("Illegal date format\n", -1);
  358.     exit(1);
  359.   }
  360.  
  361. /* Convert the time into Minix time - zone independent code */
  362.   {
  363.     time_t utctime;                     /* guess at unix time */
  364.     time_t nextbit;                     /* next bit to try */
  365.     int rv;                             /* result of try */
  366.     struct tm *tmp;                     /* local time conversion */
  367.  
  368. #define COMPARE(a,b)    ((a) != (b)) ? ((a) - (b)) :
  369. /* [<][>][^][v][top][bottom][index][help] */
  370.  
  371.     utctime = 1;
  372.     do {
  373.       nextbit = utctime;
  374.       utctime = nextbit << 1;
  375.     } while (utctime >= 1);
  376.  
  377.     for (utctime = 0; ; nextbit >>= 1) {
  378.  
  379.       utctime |= nextbit;
  380.       tmp = localtime(&utctime);
  381.       if (tmp == 0) continue;
  382.  
  383.       rv = COMPARE(tmp->tm_year,    tm.tm_year)
  384.            COMPARE(tmp->tm_mon + 1, tm.tm_mon)
  385.            COMPARE(tmp->tm_mday,    tm.tm_mday)
  386.            COMPARE(tmp->tm_hour,    tm.tm_hour)
  387.            COMPARE(tmp->tm_min,     tm.tm_min)
  388.            COMPARE(tmp->tm_sec,     tm.tm_sec)
  389.            0;
  390.  
  391.       if (rv > 0)
  392.         utctime &= ~nextbit;
  393.       else if (rv == 0)
  394.         break;
  395.  
  396.       if (nextbit == 0) {
  397.         uflag = 1;
  398.         outfd = 2;
  399.         pstring("Inexact conversion to UTC from ", -1);
  400.         fmtdate("%c\n", utctime, localtime(&utctime) );
  401.         exit(1);
  402.       }
  403.     }
  404.     return utctime;
  405.   }
  406. }
  407.  
  408. /* (Extended) Posix prototype of date. */
  409. void usage()
  410. /* [<][>][^][v][top][bottom][index][help] */
  411. {
  412.   outfd = 2;
  413.   pstring("Usage: date [-qsu] [-t seconds] [[MMDDYY]hhmm[ss]] [+format]\n", -1);
  414.   exit(1);
  415. }
  416. /* [<][>][^][v][top][bottom][index][help] */
  417.